import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.JPanel;

public class Core extends JPanel implements Tickable {   
    private java.util.List<Car> carList = new ArrayList<Car>(); 
    private boolean paused = true;         //< Are we stopped from moving?

    public static final int HEIGHT = 200;
    public static final int WIDTH = 1000;

    // inputs
    CrispVariableBox variables;

    // solve parameters
    private final double dt;
    private final int numIterations;

    public Core (String label, CrispVariableBox box) {     
        this.variables = box;
        this.setPreferredSize( new Dimension(WIDTH, HEIGHT) );
        this.setMaximumSize( new Dimension(WIDTH, HEIGHT) );
        this.setMinimumSize( new Dimension(WIDTH, HEIGHT) );

        createCars();

        // defaults
        this.dt = 0.250; // frequency of update, in sec.
        this.numIterations = 1;
    } 

    public int getNumCars() {
    	return this.carList.size();
    }
    
    public Car getCar(int index) {
    	return this.carList.get(index);
    }
    
    private void createCars() {
        assert variables != null: "Make sure we've received our inputbox by now.";
        int x = WIDTH-100;
        int y = 100;
        double velocity = variables.getInitialVelocity();
        Color[] colors = { Color.blue, Color.red, Color.green };
        Car previousCar = null;
      
        for( Color color : colors ) {
            // should we use the same FuzzyAdapter for all cars?
            FuzzyAdapter fAdapt = new FuzzyAdapter( variables ); 
            Car c = new Car (previousCar, x, y, fAdapt, color);

            // uncomment below to make cars in different lanes
            //y += HEIGHT/colors.length;

            // add cars so we can move them
            carList.add(c);
            previousCar = c;
        }
        resetToInitial();
        assert null != carList.get(0) : "Must have a lead car";
        for( Car c  : carList ) {
            c.setLeadCar( carList.get(0) );
        }
    }

    public void resetToInitial() {
        assert variables != null: "Make sure we've received our inputbox by now.";

        int x = WIDTH-100;
        int i = 0;

        // TODO: use different initial values for each car
        for (Car c: carList) {
            c.reset( x );
            x -= variables.getInitialDistance(i) + (double)c.getSizeInPixels()*2.0;

            ++i;
        }
    }

    public boolean getPaused() {
        return this.paused;
    }
    public void togglePaused() {
        this.paused = !this.paused;
        this.repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        // update model
        updateCars();

        // draw
        for(Car c : carList) {
            c.paint(g);
        }

        Rectangle r = g.getClipBounds();
        g.setColor(Color.white);
        g.drawString("Cars move relative to the lead (blue) car.", (int)r.width/2-130, HEIGHT-15);

        if ( this.paused ) {
            g.setColor( Color.yellow );
            g.setFont( g.getFont().deriveFont( 72.0f ) );
            g.drawString( "Paused", (int)r.width/2-130, (int)r.height/2 );
        }
    }

    private void updateCars() {
        // update starting at the back of the pack
        ListIterator<Car> i = carList.listIterator( carList.size() );
        for ( Car c = i.previous(); ; c = i.previous() )
        {
            c.pre_iteration();
            c.update(dt, 10);
            c.post_iteration();

            // now that we've used value, check if there's another
            if ( !i.hasPrevious() ) {
                break;
            }
        }
    }

    public void tick() {
        this.repaint();
    }
}
